/* Copyright (c) 2024 Qualcomm Technologies International, Ltd. */
/* %%version */

#include "gatt_ots_client_init.h"
#include "gatt_ots_client_discovery.h"
#include "gatt_ots_client_common_util.h"
#include "gatt_ots_client_indication.h"
#include "gatt_ots_client_select_object.h"
#include "gatt_ots_client_read_object_metadata.h"
#include "gatt_ots_client_read_object.h"
#include "gatt_ots_client_con.h"
#include "gatt_ots_client_abort.h"
#include "gatt_ots_client_filter_object.h"
#ifdef CSR_STREAMS_ENABLE
#include "gatt_ots_client_streams.h"
#endif

static void otscHandleReadValueCfm(GOTSC *const gattOtsClient,
                                   const CsrBtGattReadCfm *readCfm)
{
    GATT_OTS_CLIENT_INFO("GOTSC: Gatt Read value Cfm received for the handle [0x%x]!\n", readCfm->handle);

    if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_READ_FEATURE_CHAR)
    { /* OTS init procedure in progress */
        if (readCfm->resultCode == CSR_BT_GATT_RESULT_SUCCESS)
        {
            if (readCfm->valueLength)
            {
                memcpy(&gattOtsClient->deviceData.supportedFeatures,
                       readCfm->value,
                       sizeof(GattOtscSupportedFeatures));
            }
            /* Register for mandatory (OACP & OLCP) control point indications */
            OtscRegisterForMandatoryIndications(gattOtsClient);
        }
        else
        {
            GattOtscSendInitCfm(gattOtsClient,
                                readCfm->resultCode,
                                readCfm->resultSupplier);
        }
        gattOtsClient->pendingCmd &= ~OTSC_PENDING_OP_READ_FEATURE_CHAR;
    }
    else if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_READ_OBJ_CONTENT &&
             (readCfm->handle == gattOtsClient->deviceData.objPropertiesHandle ||
              readCfm->handle == gattOtsClient->deviceData.objSizeHandle))
    { /* OTS read content procedure in progress */
        OtscHandleReadCfmToReadObjectContent(gattOtsClient, readCfm);
    }
    else
    { /* Read Metadata charac requested by App */
        OtscHandleReadCfmToReadObjectMetadata(gattOtsClient, readCfm);
    }
}

static void otscHandleInternalWriteValueCfm(GOTSC *const gattOtsClient,
                                            const CsrBtGattWriteCfm *writeCfm)
{
    GATT_OTS_CLIENT_INFO("GOTSC: Gatt internal write Cfm received for the handle [0x%x]!\n", writeCfm->handle);

    if (writeCfm->handle == gattOtsClient->deviceData.objActionControlPointCCCDHandle)
    { /* OACP control point handle */
        gattOtsClient->pendingCmd &= ~OTSC_PENDING_OP_WRITE_OACP_CCCD;

        if (writeCfm->resultCode == CSR_BT_GATT_RESULT_SUCCESS)
        {
            /* Go for OLCP's CCD configuration now */
            if (gattOtsClient->deviceData.objListControlPointCCCDHandle)
            {
                uint8* olcpValue = (uint8*)(CsrPmemZalloc(GATT_OTS_CLIENT_CHARACTERISTIC_CONFIG_SIZE));

                olcpValue[0] = OTS_INDICATION_VALUE;
                olcpValue[1] = 0;

                CsrBtGattWriteReqSend(gattOtsClient->srvcElem->gattId,
                                      gattOtsClient->srvcElem->cid,
                                      gattOtsClient->deviceData.objListControlPointCCCDHandle,
                                      0,
                                      GATT_OTS_CLIENT_CHARACTERISTIC_CONFIG_SIZE,
                                      olcpValue);

                gattOtsClient->pendingCmd |= OTSC_PENDING_OP_WRITE_OLCP_CCCD;
            }
            else
            {
                /* Go for L2cap registration for OTS PSM */
                OtscRegisterOtsL2capChannel(gattOtsClient);
            }
        }
        else
        {
            GattOtscSendInitCfm(gattOtsClient,
                                writeCfm->resultCode,
                                writeCfm->resultSupplier);
        }
    }
    else
    { /* OLCP control point handle */
        gattOtsClient->pendingCmd &= ~OTSC_PENDING_OP_WRITE_OLCP_CCCD;

        if (writeCfm->resultCode == CSR_BT_GATT_RESULT_SUCCESS)
        {
            /* Go for L2cap registration for OTS PSM */
            OtscRegisterOtsL2capChannel(gattOtsClient);
        }
        else
        {
            GattOtscSendInitCfm(gattOtsClient,
                                writeCfm->resultCode,
                                writeCfm->resultSupplier);
        }
    }
}

static void otscHandleExternalWriteValueCfm(GOTSC *const gattOtsClient,
                                            const CsrBtGattWriteCfm *writeCfm)
{
    GATT_OTS_CLIENT_INFO("GOTSC: Gatt external write value Cfm received for the handle [0x%x]!\n", writeCfm->handle);

    if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_OLCP_PROCEDURE &&
        writeCfm->handle == gattOtsClient->deviceData.objListControlPointHandle)
    {
        /* Handle write CFM messages for OLCP procedures */
        OtscHandleWriteCfmToSelectObject(gattOtsClient, writeCfm);
    }
    else if (writeCfm->handle == gattOtsClient->deviceData.objActionControlPointHandle)
    {
        if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_ABORT_PROCEDURE)
        {
            /* Handle write CFM messages for OACP abort procedure */
            OtscHandleWriteCfmToAbort(gattOtsClient, writeCfm);
        }
        else if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_READ_OBJ_CONTENT)
        {
            /* Handle write CFM messages for OACP read procedure */
            OtscHandleWriteCfmToReadObjectContent(gattOtsClient, writeCfm);
        }
        else
        {
            /* Handle other OACP procedures */
        }
    }
    else if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_WRITE_OTHER_CCCD)
    {
        OtscHandleWriteCfmToRegisterInd(gattOtsClient, writeCfm);
    }
    else if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_FILTER_OBJ)
    {
        OtscHandleWriteCfmToFilterObject(gattOtsClient, writeCfm);
    }
    else
    {
        /* Not expected to come here */
        GATT_OTS_CLIENT_ERROR("GOTSC: GATT Write CFM received for unknown procedure(%d)!\n", gattOtsClient->pendingCmd);
    }
}

static void otscHandleWriteValueCfm(GOTSC *const gattOtsClient,
                                    const CsrBtGattWriteCfm *writeCfm)
{
    GATT_OTS_CLIENT_INFO("GOTSC: Gatt Write value cfm received for the handle [0x%x]!\n", writeCfm->handle);

    if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_WRITE_OACP_CCCD ||
        gattOtsClient->pendingCmd & OTSC_PENDING_OP_WRITE_OLCP_CCCD)
    {
        /* Handle internal(OTS client) write responses */
        otscHandleInternalWriteValueCfm(gattOtsClient, writeCfm);
    }
    else
    {
        /* Handle external(application) write responses */
        otscHandleExternalWriteValueCfm(gattOtsClient, writeCfm);
    }
}

static void otscHandleGattMessage(GOTSC *gattOtsClient, MsgId id, Msg msg)
{
    switch (id)
    {
        case CSR_BT_GATT_DISCOVER_CHARAC_CFM:
        {
            OtscHandleDiscoverCharacteristicsCfm(gattOtsClient,
                (const GATT_MANAGER_DISCOVER_ALL_CHARACTERISTICS_CFM_T *)msg);
            break;
        }

        case CSR_BT_GATT_DISCOVER_CHARAC_DESCRIPTORS_CFM:
        {
            OtscHandleDiscoverCharacDescriptorsCfm(gattOtsClient,
                (const GATT_MANAGER_DISCOVER_ALL_CHARACTERISTIC_DESCRIPTORS_CFM_T *)msg);
            break;
        }

        case CSR_BT_GATT_READ_CFM:
        {
            otscHandleReadValueCfm(gattOtsClient,
                (const CsrBtGattReadCfm *) msg);
            break;
        }

        case CSR_BT_GATT_WRITE_CFM:
        {
            otscHandleWriteValueCfm(gattOtsClient,
                (const CsrBtGattWriteCfm*) msg);
            break;
        }

        case CSR_BT_GATT_CLIENT_INDICATION_IND:
        {
            OtscHandleClientIndication(gattOtsClient,
                (const CsrBtGattClientIndicationInd *) msg);
            break;
        }

        default:
        {
            /* Unrecognised GATT Manager message */
            GATT_OTS_CLIENT_WARNING("GOTSC: Unknown Gatt message Id[0x%x]!\n", id);
            break;
        }
    }
    CsrBtGattFreeUpstreamMessageContents(CSR_BT_GATT_PRIM, msg);
}

static void otscHandleInternalMessage(GOTSC * gattOtsClient, MsgId id, Msg msg)
{
    GATT_OTS_CLIENT_INFO("GOTSC: Handling Internal Message Id[0x%x]!\n", id);

    if (gattOtsClient)
    {
        switch(id)
        {
            case OTSC_INTERNAL_MSG_REG_INDICATION_REQ:
            {
                OtscHandleInternalMsgRegisterForIndication(gattOtsClient,
                    (OtscInternalMsgRegIndication*) msg);
                break;
            }

            case OTSC_INTERNAL_MSG_SELECT_OBJ_REQ:
            {
                OtscHandleInternalMsgSelectObject(gattOtsClient,
                    (OtscInternalMsgSelectObject*)msg);
                break;
            }

            case OTSC_INTERNAL_MSG_READ_OBJ_REQ:
            {
                OtscHandleInternalMsgReadObject(gattOtsClient,
                    (OtscInternalMsgReadObject*)msg);
                break;
            }

            case OTSC_INTERNAL_MSG_ABORT_REQ:
            {
                OtscHandleInternalMsgAbort(gattOtsClient,
                    (OtscInternalMsgAbort*)msg);
                break;
            }

            case OTSC_INTERNAL_MSG_READ_OBJ_METADATA_REQ:
            {
                OtscHandleInternalMsgReadObjectMetadata(gattOtsClient,
                    (OtscInternalMsgReadObjectMetadata*)msg);
                break;
            }

            case OTSC_INTERNAL_MSG_FILTER_OBJ_REQ:
            {
                OtscHandleInternalMsgFilterObject(gattOtsClient,
                    (OtscInternalMsgFilterObject*)msg);
                break;
            }

            case OTSC_INTERNAL_MSG_OPEN_OTS_CHANNEL_REQ:
            case OTSC_INTERNAL_MSG_CLOSE_OTS_CHANNEL_REQ:
            {
                OtscHandleInternalMsgOpenOrCloseOtsChannel(gattOtsClient, id);
                break;
            }

            default:
            {
                /* Internal unrecognised messages */
                GATT_OTS_CLIENT_WARNING("GOTSC: Unknown Internal Message received [0x%x]!\n", id);
                break;
            }
        }
    }
}

static void otscHandleCmMessage(GOTSC *gattOtsClient, MsgId id, Msg msg)
{
    switch (id)
    {
        case CSR_BT_CM_L2CA_REGISTER_CFM:
        {
            CsrBtCmL2caRegisterCfm *cfm = (CsrBtCmL2caRegisterCfm*)msg;
            OtscHandleCmL2capRegisterCfm(gattOtsClient, cfm);
            break;
        }

        case CM_L2CA_TP_CONNECT_CFM:
        {
            CsrBtCmL2caTpConnectCfm *cfm = (CsrBtCmL2caTpConnectCfm*)msg;
            OtscHandleCmL2capConnectCfm(gattOtsClient, cfm);
            break;
        }

        case CSR_BT_CM_L2CA_DISCONNECT_IND:
        {
            CsrBtCmL2caDisconnectInd *ind = (CsrBtCmL2caDisconnectInd*)msg;
            OtscHandleCmL2capDisconnectInd(gattOtsClient, ind);
            break;
        }

#ifndef CSR_STREAMS_ENABLE
        case CSR_BT_CM_L2CA_DATA_IND:
        {
            CsrBtCmL2caDataInd *ind = (CsrBtCmL2caDataInd*)msg;
            OtscHandleCmDataInd(gattOtsClient, ind);
            break;
        }
#endif

        default:
        {
            /* Internal unrecognised messages */
            GATT_OTS_CLIENT_WARNING("GOTSC: Unknown CM primitive Id [0x%x]!\n", id);
            break;
        }
    }
}

void GattOtscMsgHandler(void **gash)
{
    CsrUint16 eventClass = 0;
    void *message        = NULL;
    GattOtsClient *inst  = *((GattOtsClient **)gash);

    if (CsrSchedMessageGet(&eventClass, &message))
    {
        switch (eventClass)
        {
            case CSR_BT_GATT_PRIM:
            {
                CsrBtGattPrim id     = *(CsrBtGattPrim *)message;
                GOTSC *gattOtsClient =  (GOTSC *) GetServiceClientByGattMsg(&inst->serviceHandleList, message);
                void *msg            =  GetGattManagerMsgFromGattMsg(message, &id);

                GATT_OTS_CLIENT_INFO("GOTSC: Handle Gatt Message Id[0x%x]\n", id);

                if (gattOtsClient)
                {
                    otscHandleGattMessage(gattOtsClient, id, msg);
                }

                if (msg!= message)
                {
                    CsrPmemFree(msg);
                }
            }
            break;

            case CSR_BT_CM_PRIM:
            {
                CsrBtCmPrim id          = *(CsrBtCmPrim *)message;
                ServiceHandle svcHandle =  INVALID_PROFILE_HANDLE;

                GATT_OTS_CLIENT_INFO("GOTSC: Handle CM Message Id[0x%x]\n", id);

                switch (id)
                {
                    case CSR_BT_CM_L2CA_REGISTER_CFM:
                    {
                        CsrBtCmL2caRegisterCfm *cfm   = (CsrBtCmL2caRegisterCfm*)message;
                        svcHandle = cfm->context;
                        break;
                    }

                    case CM_L2CA_TP_CONNECT_CFM:
                    {
                        CsrBtCmL2caTpConnectCfm *cfm  = (CsrBtCmL2caTpConnectCfm*)message;
                        svcHandle = cfm->context;
                        break;
                    }

                    case CSR_BT_CM_L2CA_DISCONNECT_IND:
                    {
                        CsrBtCmL2caDisconnectInd *ind = (CsrBtCmL2caDisconnectInd*)message;
                        svcHandle = ind->context;
                        break;
                    }

#ifndef CSR_STREAMS_ENABLE
                    case CSR_BT_CM_L2CA_DATA_IND:
                    {
                        CsrBtCmL2caDataInd *ind       = (CsrBtCmL2caDataInd*)message;
                        svcHandle = ind->context;
                        break;
                    }
#endif
                    default:
                    {
                        GATT_OTS_CLIENT_WARNING("GOTSC: Unknown CM primitive [0x%x]!\n", id);
                        break;
                    }
                }

                if (svcHandle != INVALID_PROFILE_HANDLE)
                {
                    GOTSC *gattOtsClient = ServiceHandleGetInstanceData(svcHandle);

                    if (gattOtsClient)
                    {
                        otscHandleCmMessage(gattOtsClient, id, message);
                    }
                    else
                    {
                        GATT_OTS_CLIENT_ERROR("GOTSC: OTS client instance not found!\n");
                    }
                }

                break;
            }

#ifdef CSR_STREAMS_ENABLE
            case MESSAGE_MORE_SPACE:
            {
                OtscMessageMoreSpaceHandler(inst, message);
                break;
            }

            case MESSAGE_MORE_DATA:
            {
                OtscMessageMoreDataHandler(inst, message);
                break;
            }
#endif
            case OTS_CLIENT_PRIM:
            {
                OtscInternalMsg id   = *(OtscInternalMsg *)message;
                GOTSC *gattOtsClient =  (GOTSC *) GetServiceClientByServiceHandle(message);
                otscHandleInternalMessage(gattOtsClient, id, message);
                break;
            }

            default:
            {
                GATT_OTS_CLIENT_WARNING("GOTSC: Client Msg not handled [0x%x]\n", eventClass);
                break;
            }
        }

        SynergyMessageFree(eventClass, message);
    }
}

